package com.css.attachment.service.impl;

import cn.hutool.core.io.FileUtil;
import cn.hutool.core.util.StrUtil;
import com.baomidou.dynamic.datasource.annotation.DSTransactional;
import com.baomidou.dynamic.datasource.toolkit.DynamicDataSourceContextHolder;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;

import com.css.attachment.entity.AttachmentInfoEntity;
import com.css.attachment.entity.ParsingResult;
import com.css.attachment.mapper.AttachmentMapper;
import com.css.attachment.service.AttachmentService;
import com.css.attachment.vo.AttachVO;
import com.css.util.ShpAnalyticUtil;
import org.apache.commons.lang3.ObjectUtils;
import org.apache.commons.lang3.StringUtils;
import org.springframework.beans.BeanUtils;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
import org.springframework.web.context.request.RequestContextHolder;
import org.springframework.web.context.request.ServletRequestAttributes;
import org.springframework.web.multipart.MultipartFile;

import javax.servlet.http.HttpServletResponse;
import java.io.*;
import java.net.URLEncoder;
import java.text.SimpleDateFormat;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Date;
import java.util.List;

/**
 * @author Dbj
 * @date 2024年08月30日  10:05
 */
@Service
public class AttachmentServiceImpl extends ServiceImpl<AttachmentMapper, AttachmentInfoEntity> implements AttachmentService {

    @Value("${shp.path}")
    private String localDir;

    /**
     * 构建文件上传实体并返回文件id和名称用于页面的数据回显 以供后续下载
     */
    @Override
    @DSTransactional
    public List<AttachVO> uploadShpFile(List<MultipartFile> files) throws Exception {
        List<AttachVO> voList = new ArrayList<>();
        List<AttachmentInfoEntity> attachmentInfoEntities = new ArrayList<>();
        String currTime = System.currentTimeMillis() + "";
        for (MultipartFile file : files) {
            if (!file.isEmpty()) {
                try {
                    //获取文件名称
                    String fileName = file.getOriginalFilename();
                    //获取文件上传的本地路径
                    String dateDir = new SimpleDateFormat("/yyyy/MM/dd").format(new Date());
                    String savePath = localDir + dateDir;
                    //构建文件
                    assert fileName != null;
                    //上传文件
                    String realFileName = uploadFile(fileName, savePath, file, currTime);
                    if (StringUtils.isBlank(realFileName)) {
                        //如果上传的不是标准的七个指定后缀的文件则跳过
                        continue;
                    }
                    //构建实体类
                    AttachmentInfoEntity attachmentInfoEntity = buildAttachment(fileName, dateDir, realFileName);
                    AttachVO vo = new AttachVO();
                    BeanUtils.copyProperties(attachmentInfoEntity, vo);
                    voList.add(vo);
                    attachmentInfoEntities.add(attachmentInfoEntity);
                } catch (Exception e) {
                    e.printStackTrace();
                    throw new RuntimeException("文件上传失败");
                }
            }
        }
        if (attachmentInfoEntities.size() > 0) {
            this.saveBatch(attachmentInfoEntities);
        }
        return voList;
    }

    /**
     * 构建附件实体数据
     */
    private AttachmentInfoEntity buildAttachment(String fileName, String dateDir, String realFileName) {
        return AttachmentInfoEntity.builder().attachId(StrUtil.uuid().replace("-", "")).attachName(fileName)
                .attachPath(dateDir + "/" + realFileName).fileDirId(localDir).isValid("1").isCompleted("1").build();
    }

    /**
     * 构建文件名称，实现文件上传
     */
    private String uploadFile(String fileName, String savePath, MultipartFile multipartFile, String currTime) throws IOException {
        // 获取文件的后缀名
        assert fileName != null;
        String preFileName = FileUtil.getPrefix(fileName);
        // dbf","prj","sbn","sbx","shp","xml","shx
        String fileType = FileUtil.getSuffix(fileName);
        // 拼文件名  真实的文件名称
        String realFileName = preFileName + "_" + currTime + "." + fileType;
        //判断文件夹是否存在如果不存在则创建
        if (!new File(savePath).exists()) {
            FileUtil.mkdir(savePath);
        }
        File file = new File(savePath, realFileName);
        multipartFile.transferTo(file);
        return realFileName;
    }

    /**
     * shp文件必须要上传的文件的后缀
     */
    private List<String> suffixList() {
        return Arrays.asList("dbf", "prj", "sbn", "sbx", "shp", "xml", "shx");
    }

    @Override
    public AttachmentInfoEntity getAttach(String id) {
        return getById(id);
    }

    @Override
    public ParsingResult getShpData(String fileIds) throws Exception {
        //.prj结尾用来校验是否为2000坐标系
        String prj = "";
        //.cpg文件用来获得编码格式,例如utf-8
        String cpg = "GBK";
        //.shp文件用来获得数据
        String shp = "";
        //根据id获取真实地址
        String[] split = fileIds.split(",");
        for (String id : split) {
            //根据id和文件名获取真实的放在磁盘上的文件
            AttachmentInfoEntity attachmentInfoEntity = getAttach(id);
            String attachPath = attachmentInfoEntity.getAttachPath();
            String substring = attachPath.substring(attachPath.length() - 4);
            if (substring.equals(".prj")) {
                prj = localDir + File.separator + attachPath;
            } else if (substring.equals(".shp")) {
                shp = localDir + File.separator + attachPath;
            }
//            else if (substring.equals(".cpg")) {
//                cpg = localDir + File.separator + attachPath;
//            }
        }
        return ShpAnalyticUtil.analytic(prj, cpg, shp);
    }

    /**
     * 统一文件名
     *
     * @param fileIds
     */
    @Override
    @Transactional(rollbackFor = Exception.class)
    public void uniformFileName(String fileIds) {
        String[] idList = fileIds.split(",");
        AttachmentInfoEntity attachRoot = getAttach(idList[0]);
        String attachRootPath = attachRoot.getAttachPath();
        String filePathCurrTime = getFilePathCurrTime(attachRootPath);
        for (int i = 1; i < idList.length; i++) {
            AttachmentInfoEntity attach = getAttach(idList[i]);
            if (getFilePathCurrTime(attach.getAttachPath()).equals(filePathCurrTime)) {
                continue;
            }
            String attachPath = attach.getAttachPath();
            String fileDiskPath = localDir + File.separator + attachPath;
            String newName = getNonSuffixFileName(attach.getAttachName()) + "_" + filePathCurrTime + "." + FileUtil.getSuffix(attach.getAttachName());
            FileUtil.rename(new File(fileDiskPath), newName, true);
            attachPath = attachPath.replace(getFilePathCurrTime(attachPath), filePathCurrTime);
            attach.setAttachPath(attachPath);
            attach.setAttachName(newName);
            this.updateById(attach);
        }
    }

    private String getFilePathCurrTime(String filePath) {
        return StringUtils.substringAfterLast(filePath, "_").replaceAll("." + FileUtil.getSuffix(StringUtils.substringAfterLast(filePath, "_")), "");
    }

    private String getNonSuffixFileName(String fileName) {
        return fileName.replaceAll("." + FileUtil.getSuffix(fileName), "");
    }

    @Override
    public List<AttachVO> uploadFile(List<MultipartFile> file) {
        List<AttachVO> voList = new ArrayList<>();
        List<AttachmentInfoEntity> attachmentInfoEntities = new ArrayList<>();
        for (int i = 0; i < file.size(); i++) {
            if (!file.get(i).isEmpty()) {
                MultipartFile multipartFile = file.get(i);
                try {
                    //获取文件名称
                    String fileName = multipartFile.getOriginalFilename();
                    //获取文件上传的本地路径
                    String dateDir = new SimpleDateFormat("/yyyy/MM/dd").format(new Date());
                    String savePath = localDir + dateDir;
                    //构建文件
                    assert fileName != null;
                    //上传文件
                    String realFileName = uploadFile(fileName, savePath, multipartFile);
                    //构建实体类
                    AttachmentInfoEntity attachmentInfoEntity = buildAttachment(fileName, dateDir, realFileName);
                    AttachVO vo = new AttachVO();
                    BeanUtils.copyProperties(attachmentInfoEntity, vo);
                    voList.add(vo);
                    attachmentInfoEntities.add(attachmentInfoEntity);
                } catch (Exception e) {
                    e.printStackTrace();
                    throw new RuntimeException("文件上传失败");
                }
            }
        }
        //保存附件到数据库
        if (ObjectUtils.isNotEmpty(attachmentInfoEntities)) {
            this.saveBatch(attachmentInfoEntities);
        }
        return voList;
    }

    private String uploadFile(String fileName, String savePath, MultipartFile multipartFile) throws IOException {
        // 获取文件的后缀名
        assert fileName != null;
        String preFileName = fileName.substring(0, fileName.lastIndexOf("."));
        // .jpg  .pdf  .txt  .docs
        String fileType = fileName.substring(fileName.lastIndexOf("."));
        // 拼文件名  真实的文件名称
        String realFileName = preFileName + "_" + System.currentTimeMillis() + fileType;
        //判断文件夹是否存在如果不存在则创建
        if (!new File(savePath).exists()) {
            new File(savePath).mkdirs();
        }
        File file = new File(savePath, realFileName);
        multipartFile.transferTo(file);
        return realFileName;
    }

    @Override
    public void downloadFile(String attachId){
        OutputStream os = null;
        InputStream is = null;
        try {
            //根据id和文件名获取真实的放在磁盘上的文件
            AttachmentInfoEntity attachmentInfoEntity = this.getById(attachId);
            String attachPath = attachmentInfoEntity.getAttachPath();
            if (org.apache.commons.lang3.StringUtils.isNotBlank(attachPath)) {
                // 防乱码
//                    String name =
//                        new String(realFileName.getBytes(StandardCharsets.UTF_8), StandardCharsets.ISO_8859_1);
                ServletRequestAttributes requestAttributes = (ServletRequestAttributes) RequestContextHolder.getRequestAttributes();
                assert requestAttributes != null;
                HttpServletResponse response = requestAttributes.getResponse();
                assert response != null;
                response.reset();
                response.setContentType("application/octet-stream");
                response.setHeader("Content-Disposition", "attachment;filename=\"" + URLEncoder.encode(attachmentInfoEntity.getAttachName(), "UTF-8") + "\"");
                // 跨域
                response.setHeader("Access-Control-Allow-Origin", "*");
                response.setHeader("Access-Control-Allow-Method", "POST,GET");
                String name = attachmentInfoEntity.getFileDirId() + attachPath;
                File file = new File(name);
                if (!file.exists()) {
                    file = new File(attachmentInfoEntity.getFileDirId() + attachPath);
                }
                is = new FileInputStream(file);

                // PrintWrite pw=response.getWriter();  或
                os = response.getOutputStream();
                int flag = 0;
                while ((flag = is.read()) != -1) {
                    os.write(flag);
                }
            }
        } catch (Exception e) {
            e.printStackTrace();
            System.out.println(e.getMessage());
        } finally {
            try {
                if (is != null) {
                    is.close();
                }
                if (os != null) {
                    os.flush();
                    os.close();
                }
            } catch (IOException e) {
                e.printStackTrace();
            }
        }
    }
}
